#include "vagsdk_util.h"

ParseDeviceInfoRs ParseDeviceInfo(JNIEnv *env, jobject deviceInfo, bool isCheckUuid) {
    ParseDeviceInfoRs rs{};
    JNIHandle *h = JNIHandle::GetInstance();

    jobject deviceType = env->GetObjectField(deviceInfo, h->fid_deviceInfo_type);
    CHECK_NULL_RETURN_THROW_API_EX(env, deviceType, "The type of DeviceInfo can't be null", rs);

    // Get type field value
    int type = env->GetIntField(deviceType, h->fid_deviceInfoType_value);
    rs.info.devicetype = type;
    env->DeleteLocalRef(deviceType);

    // Get and set uuid
    if (isCheckUuid) {
        auto uuid = (jstring) env->GetObjectField(deviceInfo, h->fid_deviceInfo_dev_uuid);
        CHECK_NULL_RETURN_THROW_API_EX(env, uuid, "The uuid can't be null", rs);

        const char *pUuid = env->GetStringUTFChars(uuid, JNI_FALSE);
        CHECK_NULL_RETURN_THROW_API_EX_AND_DELETE_REF(env, pUuid, "Failed call GetStringUTFChars for uuid", rs, uuid);

        rs.uuid = pUuid;
        env->ReleaseStringUTFChars(uuid, pUuid);
        env->DeleteLocalRef(uuid);
    }

    // Get ip value
    auto ip = (jstring) env->GetObjectField(deviceInfo, h->fid_deviceInfo_ip);
    CHECK_NULL_RETURN_THROW_API_EX(env, ip, "The ip can't be null or empty", rs);

    const char *pIp = env->GetStringUTFChars(ip, JNI_FALSE);
    CHECK_NULL_RETURN_THROW_API_EX_AND_DELETE_REF(env, pIp, "The ip can't be null or empty", rs, ip);
    strncpy(rs.info.ipaddr, pIp, sizeof(rs.info.ipaddr) - 1);
    rs.info.ipaddr[sizeof(rs.info.ipaddr) - 1] = '\0'; // 确保字符串终结符
    env->ReleaseStringUTFChars(ip, pIp);
    env->DeleteLocalRef(ip);

    // Get port
    auto port = env->GetIntField(deviceInfo, h->fid_deviceInfo_port);
    if (port <= 0) {
        THROW_VAG_EX(env, "The port value is illegal");
        return rs;
    }
    rs.info.port = port;

    // Get username
    auto username = (jstring) env->GetObjectField(deviceInfo, h->fid_deviceInfo_username);
    if (username != nullptr) {
        const char *pUsername = env->GetStringUTFChars(username, JNI_FALSE);
        CHECK_NULL_RETURN_THROW_API_EX_AND_DELETE_REF(env, pUsername, "Failed call GetStringUTFChars for username", rs, username);
        strncpy(rs.info.username, pUsername, sizeof(rs.info.username) - 1);
        rs.info.username[sizeof(rs.info.username) - 1] = '\0'; // 确保字符串终结符
        env->ReleaseStringUTFChars(username, pUsername);
        env->DeleteLocalRef(username);
    }

    // Get password
    auto password = (jstring) env->GetObjectField(deviceInfo, h->fid_deviceInfo_password);
    if (password != nullptr) {
        const char *pPassword = env->GetStringUTFChars(password, JNI_FALSE);
        CHECK_NULL_RETURN_THROW_API_EX_AND_DELETE_REF(env, pPassword, "Failed call GetStringUTFChars for password", rs, password);
        strncpy(rs.info.password, pPassword, sizeof(rs.info.password) - 1);
        rs.info.password[sizeof(rs.info.password) - 1] = '\0'; // 确保字符串终结符
        env->ReleaseStringUTFChars(password, pPassword);
        env->DeleteLocalRef(password);
    }

    // Get linkMode
    jobject linkMode = env->GetObjectField(deviceInfo, h->fid_deviceInfoLinkMode);
    CHECK_NULL_RETURN_THROW_API_EX(env, linkMode, "The linkMode can't be null", rs);
    rs.info.link_mode = env->GetIntField(linkMode, h->fid_deviceInfoLinkMode_value);
    env->DeleteLocalRef(linkMode);

    rs.isSuccess = true;
    return rs;
}

ParseProxyShowStringInfoRs ParseProxyShowStringInfo(JNIEnv *env, jobject showString) {
    ParseProxyShowStringInfoRs rs{};
    JNIHandle *h = JNIHandle::GetInstance();

    jobject osdInfoList = env->GetObjectField(showString, h->fid_showStringInfo_osdInfoList);
    CHECK_NULL_RETURN_THROW_API_EX(env, osdInfoList, "The osdInfoList can't be null", rs);

    char buf[256];
    jint osdInfoListSize = env->CallIntMethod(osdInfoList, h->mid_list_size);
    if (osdInfoListSize <= 0 || osdInfoListSize > PROXY_MAX_STRINGNUM) {
        sprintf(buf, "The size of osdInfoList must between 1-%d", PROXY_MAX_STRINGNUM);
        env->DeleteLocalRef(osdInfoList);
        THROW_VAG_EX(env, buf);
        return rs;
    }
    rs.info.dwSize = osdInfoListSize;
    for (int i = 0; i < osdInfoListSize; i++) {
        jobject osdInfo = env->CallObjectMethod(osdInfoList, h->mid_list_get, i);

        jobject showStringValObj = env->GetObjectField(osdInfo, h->fid_osdInfo_iShowString);
        jlong showStringVal = env->GetLongField(showStringValObj, h->fid_long_value);

        jobject stringSizeObj = env->GetObjectField(osdInfo, h->fid_osdInfo_iStringSize);
        jlong stringSize = env->GetLongField(stringSizeObj, h->fid_long_value);

        if (stringSize > 44) {
            env->DeleteLocalRef(osdInfo);
            env->DeleteLocalRef(osdInfoList);
            THROW_VAG_EX(env, "The iStringSize of osdInfo can't greater than 44");
            return rs;
        }

        jobject topLeftXObj = env->GetObjectField(osdInfo, h->fid_osdInfo_iShowStringTopLeftX);
        jlong topLeftX = env->GetLongField(topLeftXObj, h->fid_long_value);

        jobject topLeftYObj = env->GetObjectField(osdInfo, h->fid_osdInfo_iShowStringTopLeftY);
        jlong topLeftY = env->GetLongField(topLeftYObj, h->fid_long_value);

        auto text = (jstring) env->GetObjectField(osdInfo, h->fid_osdInfo_text);

        // Convert Java OsdInfo to _proxy_osd_info
        _proxy_osd_info &cOsdInfo = rs.info.struStringInfo[i];
        if (text != nullptr) {
            const char *tmpText = env->GetStringUTFChars((jstring) text, JNI_FALSE);
            CHECK_NULL_RETURN_THROW_API_EX_AND_DELETE_REF3(env, tmpText, "Failed call GetStringUTFChars for "
                                                                         "osdInfo's text",
                                                           rs, text, osdInfo, osdInfoList);
            strcpy(cOsdInfo.sString, tmpText);
            env->ReleaseStringUTFChars(text, tmpText);
            env->DeleteLocalRef(text);
        }

        cOsdInfo.iStringSize = stringSize;
        cOsdInfo.iShowString = showStringVal;
        cOsdInfo.iShowStringTopLeftX = topLeftX;
        cOsdInfo.iShowStringTopLeftY = topLeftY;

        env->DeleteLocalRef(osdInfo);

    }
    rs.isSuccess = true;
    env->DeleteLocalRef(osdInfoList);
    return rs;
}

jDauDeviceInfo ConvertFromDauDeviceInfo(JNIEnv *env, _dau_device_info dauInfo) {
    JNIHandle *h = JNIHandle::GetInstance();
    jstring name = env->NewStringUTF(dauInfo._dev_name);
    jstring serialNum = env->NewStringUTF(dauInfo._dev_serialnum);
    jstring version = env->NewStringUTF(to_string(dauInfo._dev_version).c_str());
    jstring type = env->NewStringUTF(to_string(dauInfo._dev_type).c_str());
    return env->NewObject(h->cls_dauDeviceInfo, h->mid_dauDeviceInfo_init, name, serialNum, version, type);
}

jDevChannelInfo ConvertFromDevChannelInfo(JNIEnv *env, _device_channel_info channelInfo) {
    JNIHandle *h = JNIHandle::GetInstance();

    jobject channelNameInfoList = NewArrayList(env);

    int channelCount = channelInfo._channel_num;
    for (int i = 0; i < channelCount; i++) {
        _channel_infos nameInfo = channelInfo._chn_info[i];
        int index = nameInfo.channel_index;
        jstring name = env->NewStringUTF(nameInfo._channel_name);
        int remoteIndex = nameInfo._remote_index;
        jobject channelNameInfo = env->NewObject(h->cls_channelNameInfo, h->mid_channelNameInfo_init, index, name,remoteIndex);
        env->CallObjectMethod(channelNameInfoList, h->mid_arraylist_add, channelNameInfo);
        env->DeleteLocalRef(name);
        env->DeleteLocalRef(channelNameInfo);
    }

    jDevChannelInfo devChannelInfo = env->NewObject(h->cls_devChannelInfo, h->mid_devChannelInfo_init, channelCount,
                                                    channelNameInfoList);

    env->DeleteLocalRef(channelNameInfoList);

    return devChannelInfo;
}

jShowStringInfo ConvertFromProxyShowStringInfo(JNIEnv *env, _proxy_showstring_info ssi) {
    JNIHandle *h = JNIHandle::GetInstance();

    jobject osdList = NewArrayList(env);
    for (auto poi : ssi.struStringInfo) {
        if (poi.iShowString == 0) {
            continue;
        }

        jobject osdObj = env->NewObject(h->cls_osdInfo, h->mid_osdInfo_init);
        env->SetLongField(osdObj, h->fid_osdInfo_iShowString, poi.iShowString);
        env->SetLongField(osdObj, h->fid_osdInfo_iStringSize, poi.iStringSize);
        env->SetLongField(osdObj, h->fid_osdInfo_iShowStringTopLeftX, poi.iShowStringTopLeftX);
        env->SetLongField(osdObj, h->fid_osdInfo_iShowStringTopLeftY, poi.iShowStringTopLeftY);

        jstring text = env->NewStringUTF(poi.sString);
        env->SetObjectField(osdObj, h->fid_osdInfo_text, text);

        env->CallObjectMethod(osdList, h->mid_arraylist_add, osdObj);

        env->DeleteLocalRef(text);
        env->DeleteLocalRef(osdObj);
    }

    jShowStringInfo showStringInfo = env->NewObject(h->cls_showStringInfo, h->mid_showStringInfo_init);
    env->SetObjectField(showStringInfo, h->fid_showStringInfo_osdInfoList, osdList);

    env->DeleteLocalRef(osdList);

    return showStringInfo;
}

ParseAlarmInfoRs ParseSetupAlarmInfo(JNIEnv *env, jobject setupAlarm) {
    ParseAlarmInfoRs rs{};
    JNIHandle *h = JNIHandle::GetInstance();

    jint dwSize = env->GetIntField(setupAlarm, h->fid_setUpAlarm_dwSize);
    jint byLevel = env->GetIntField(setupAlarm, h->fid_setUpAlarm_byLevel);
    jint byAlarmInfoType = env->GetIntField(setupAlarm, h->fid_setUpAlarm_byAlarmInfoType);
    jint byRetAlarmTypeV40 = env->GetIntField(setupAlarm, h->fid_setUpAlarm_byRetAlarmTypeV40);
    jint byRetVQDAlarmType = env->GetIntField(setupAlarm, h->fid_setUpAlarm_byRetVQDAlarmType);
    jint byRetDevInfoVersion = env->GetIntField(setupAlarm, h->fid_setUpAlarm_byRetDevInfoVersion);
    jint byFaceAlarmDetection = env->GetIntField(setupAlarm, h->fid_setUpAlarm_byFaceAlarmDetection);
    jint bySupport = env->GetIntField(setupAlarm, h->fid_setUpAlarm_bySupport);
    jint byBrokenNetHttp = env->GetIntField(setupAlarm, h->fid_setUpAlarm_byBrokenNetHttp);
    jint wTaskNo = env->GetIntField(setupAlarm, h->fid_setUpAlarm_wTaskNo);
    jint byDeployType = env->GetIntField(setupAlarm, h->fid_setUpAlarm_byDeployType);
    jint bySubScription = env->GetIntField(setupAlarm, h->fid_setUpAlarm_bySubScription);
    jint byBrokenNetHttpV60 = env->GetIntField(setupAlarm, h->fid_setUpAlarm_byBrokenNetHttpV60);
    jint byRes1 = env->GetIntField(setupAlarm, h->fid_setUpAlarm_byRes1);
    jint byAlarmTypeURL = env->GetIntField(setupAlarm, h->fid_setUpAlarm_byAlarmTypeURL);
    jint byCustomCtrl = env->GetIntField(setupAlarm, h->fid_setUpAlarm_byCustomCtrl);

    _setup_alarm_info alarmInfo{};
    alarmInfo.dwSize = sizeof(_setup_alarm_info);
    alarmInfo.byLevel = byLevel;
    alarmInfo.byAlarmInfoType = byAlarmInfoType;
    alarmInfo.byRetAlarmTypeV40 = byRetAlarmTypeV40;
    alarmInfo.byRetVQDAlarmType = byRetVQDAlarmType;
    alarmInfo.byRetDevInfoVersion = byRetDevInfoVersion;
    alarmInfo.byFaceAlarmDetection = byFaceAlarmDetection;
    alarmInfo.bySupport = bySupport;
    alarmInfo.byBrokenNetHttp = byBrokenNetHttp;
    alarmInfo.wTaskNo = wTaskNo;
    alarmInfo.byDeployType = byDeployType;
    alarmInfo.bySubScription = bySubScription;
    alarmInfo.byBrokenNetHttpV60 = byBrokenNetHttpV60;
    alarmInfo.byRes1 = byRes1;
    alarmInfo.byAlarmTypeURL = byAlarmTypeURL;
    alarmInfo.byCustomCtrl = byCustomCtrl;


    auto jbyteByRes4 = (jbyteArray) env->GetObjectField(setupAlarm, h->fid_setUpAlarm_byRes4);
    if (jbyteByRes4 != nullptr)
    {
        //获取长度
        jsize alen = env->GetArrayLength(jbyteByRes4);
        jbyte *elements = env->GetByteArrayElements(jbyteByRes4, JNI_FALSE);
        memcpy(alarmInfo.byRes4, elements, sizeof(uint8_t) * alen);

        env->DeleteLocalRef(jbyteByRes4);
        env->ReleaseByteArrayElements(jbyteByRes4, elements, 0);
    }


    rs.info = alarmInfo;
    rs.isSuccess = true;
    return rs;
}


